#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/socket.h>
#include <unistd.h>


#include "protocolArbitre.h"
#include "fonctionsTCP.h"
#include "client.h"

#define false 0
#define FALSE 0
#define true 1
#define TRUE 1

int main( int argc, char** argv ){
	int socket;
	int port_arbitre;
	int id_joueur;
	int id_adversaire;
	int finTournoi;
	int premier;
	int numCoup;
	int partiContinue;
	int err;
	char* nom_arbitre;
	char* nom_joueur = (char*) NULL;
	TypValCoup validite;
	TypPosition depart;
	TypPosition arrivee;
	int taille = TAIL_CHAIN;
	
	TypPropCoup typeCoup_moi = DEPL;
	TypBooleen bloque_moi = FAUX;
	
	TypPropCoup typeCoup_adv;
	TypBooleen bloque_adv;
	
	depart.axeLettre = AXE_A;
	depart.axeChiffre = AXE_UN;
	
	arrivee.axeLettre = AXE_QUATRE;
	arrivee.axeChiffre = AXE_D;
	
#if DEBUG == 1
	printf("***\tDEBUG ON\n\n");
#endif
	if( argc != 3 ){
		printf("USAGE:\t./client ADDRESS PORT\n\nADDRESS:\tl'adresse du serveur\nPORT:\t\tle numero du port du serveur\n");
		return -6;
	}
	port_arbitre = atoi( argv[2] );
	nom_arbitre = argv[1];

	printf("Votre nom:\t");
	getline(&nom_joueur,(size_t*) &taille, stdin);
	{
		int tailleNom = strlen( nom_joueur );
		if( nom_joueur[tailleNom-1] == '\n' )
			nom_joueur[tailleNom-1] = '\0';
	}
#if DEBUG == 1
	printf("port:\t%d\nadresse:\t%s\nvotre nom: %s\n\n", port_arbitre, nom_arbitre, nom_joueur);
#endif

	socket = socketClient(nom_arbitre, port_arbitre);
	if( socket < 0 ){
		printf("Erreur! La socket n'a pas pu etre crée!\n");
		return -1;
	}
#if DEBUG == 1
	printf("Creation de la socket OK\n\n");
#endif
	
	err = envoi_identification( socket, nom_joueur);
	if( err < 0 ){
		printf("Erreur! l'envoi de l'identification n'a pas pu etre realise\n");
		return -2;
	}
	
	err = retour_identification(socket, &id_joueur);		
	if( err != ERR_OK ){
		printf("Erreur! le retour de l'identification donne une erreur.\n");
		return -3;
	}
	
	err = envoi_partie( socket, id_joueur );
	if( err < 0 ){
		printf("Erreur! l'envoi de l'erreur ne s'est pas deroule correctement.\n");
		return -4;
	}
	
	err = retour_partie( socket, &id_adversaire, &finTournoi, &premier);
	if( err != ERR_OK ){
		printf("Erreur! le retour de la demande de partie comporte une erreur.\n");
		return -5;
	}
	
	while( !finTournoi ){
#if DEBUG == 1
	printf("Debut de partie.\n");
#endif
		typeCoup_moi = DEPL;
		partiContinue = 1;
		numCoup = 0;
		do{
#if DEBUG == 1
	printf("tour n°%d\n", numCoup);
#endif
			if( premier ){
				if( numCoup > 10 )
					typeCoup_moi = GAGNE;
				envoi_coup(socket, ROUGE, typeCoup_moi, bloque_moi, depart, arrivee, numCoup);
				retour_coup(socket, &validite);
				if( validite != VALID || typeCoup_moi == GAGNE || typeCoup_moi == PERD || typeCoup_moi == NULLE ){
					partiContinue = 0;
#if DEBUG == 1
					if( typeCoup_moi == GAGNE )
						printf("Je gagne!\n");
					else if( typeCoup_moi == PERD )
						printf("Je perd!\n");
					else
						printf("Mon coup n'est pas valide. Je perd.\n");
#endif
				}else{
					retour_coup( socket, &validite);
					if( validite != VALID )
						partiContinue = 0;
					else{
						reception_requete_coup( socket, &typeCoup_adv, &bloque_adv, &depart, &arrivee);
						if( typeCoup_adv == GAGNE )
							partiContinue = 0;
					}
				}
			}else{
				retour_coup( socket, &validite);
				if( validite != VALID )
					partiContinue = false;
				else{
					reception_requete_coup( socket, &typeCoup_adv, &bloque_adv, &depart, &arrivee);
					if( typeCoup_adv == GAGNE || typeCoup_adv == PERD ){
						partiContinue = 0;					
#if DEBUG == 1
						if( typeCoup_adv == GAGNE )
							printf("Je perd!\n");
						else if( typeCoup_adv == PERD )
							printf("Je gagne!\n");
#endif
					}else{
						if( numCoup > 10 )
							typeCoup_moi = GAGNE;
						envoi_coup(socket, ROUGE, typeCoup_moi, bloque_moi, depart, arrivee, numCoup);
						retour_coup( socket, &validite);
						if( validite != VALID )
							partiContinue = false;
					}
				}
				
			}
		numCoup++;
		}while(partiContinue );
#if DEBUG == 1
		printf("fin de la partie\n");
#endif
		envoi_partie( socket, id_joueur );
		retour_partie( socket, &id_adversaire, &finTournoi, &premier);
	}
	
#if DEBUG == 1
	printf("Arret du programme\n");
#endif
	shutdown( socket, 2);
	close( socket );
	
	free( nom_joueur );
	return 0;
}

int envoi_identification( int socket, char* nom_joueur ){
	TypIdentificationReq requete_ident;
	requete_ident.idRequest = IDENTIFICATION;
	strcpy(requete_ident.nom, nom_joueur );
#if DEBUG == 1
	printf("\tREQUETE: IDENTIFICATION - %s\n",requete_ident.nom);
#endif
	return send(socket, &requete_ident, sizeof( TypIdentificationReq ), 0);
}

int retour_identification( int socket, int* id_joueur ){
	TypIdentificationRep reponse_ident;
	recv(socket, &reponse_ident, sizeof( TypIdentificationRep ), 0);
	*id_joueur = reponse_ident.joueur;
#if DEBUG == 1
	printf("\tREPONSE: IDENTIFICATION - err: %d | id: %d\n",reponse_ident.err, reponse_ident.joueur);
#endif
	return reponse_ident.err;
}

int envoi_partie( int socket, int id_joueur ){
	TypPartieReq requete;
	requete.joueur = id_joueur;
	requete.idRequest = PARTIE;
#if DEBUG == 1
	printf("\tREQUETE: PARTIE - id joueur: %d\n", requete.joueur);
#endif
	return send( socket, &requete, sizeof( TypPartieReq ), 0);
}

int retour_partie( int socket, int* adversaire, int* finTournoi, int* premier ){
	TypPartieRep reponse;
	recv( socket, &reponse, sizeof( TypPartieRep ), 0);
	*adversaire = reponse.adversaire;
	*finTournoi = reponse.finTournoi;
	*premier = reponse.premier;
#if DEBUG == 1
	printf("\tREPONSE: PARTIE - err: %d | adversaire: %d",reponse.err, reponse.adversaire);
	printf(" | finTournoi: %d ", *finTournoi);
	if( *finTournoi == VRAI )
		printf("oui | premier: %d ", *premier);
	else if( *finTournoi == FAUX)
		printf("non | premier: %d ", *premier);
	else
		printf("INCONNU | premier: %d", *premier);
	
	if( *premier == VRAI )
		printf("oui\n");
	else if( *premier == FAUX )
		printf("non\n");
	else
		printf("INCONNU\n");
#endif
	return reponse.err;
}

int envoi_coup( int socket, TypPiece piece, TypPropCoup typeCoup, TypBooleen bloque, TypPosition depart,
								TypPosition arrivee, int numCoup){
	TypCoupReq requete;
	requete.idRequest = COUP;
	requete.couleurPiece = piece;
	requete.propCoup = typeCoup;
	requete.bloq = bloque;
	requete.caseDepPiece = depart;
	requete.caseArrPiece = arrivee;
	requete.numeroDuCoup = numCoup;
	
#if DEBUG == 1
	printf("\tREQUETE: COUP - couleur: %d | type coup: %d | bloque: %d | numero coup: %d | ", requete.couleurPiece, requete.propCoup,  requete.bloq, requete.numeroDuCoup);
	printf("depart x: %d y: %d | arrivee x: %d y: %d\n", requete.caseDepPiece.axeLettre, requete.caseDepPiece.axeChiffre, requete.caseArrPiece.axeLettre, requete.caseArrPiece.axeChiffre);	
#endif
	return send(socket, &requete, sizeof( TypCoupReq ), 0);
}

int retour_coup( int socket, TypValCoup* isValide){
	TypCoupRep reponse;
	recv(socket, &reponse, sizeof( TypCoupRep ), 0);
	*isValide = reponse.validCoup;
#if DEBUG == 1
	printf("\tREPONSE: COUP - valide: %d->%d\n", reponse.validCoup, *isValide);
#endif
	return reponse.err;
}

int reception_requete_coup( int socket, TypPropCoup* typeCoup, TypBooleen* bloque, TypPosition* depart, TypPosition* arrivee){
	TypCoupReq requete;
	int err = recv( socket, &requete, sizeof( TypCoupReq), 0);
	*typeCoup = requete.propCoup;
	*bloque = requete.bloq;
	*depart = requete.caseDepPiece;
	*arrivee = requete.caseArrPiece;
#if DEBUG == 1
	printf("\tREPONSE: COUP ADV - typeCoup: %d | bloque: %d | depart x: %d y: %d | arrivee x: %d y: %d\n", *typeCoup, *bloque, depart->axeLettre, depart->axeChiffre, arrivee->axeLettre, arrivee->axeChiffre);
#endif
	return err;
}